package cc.magicjson.mall.order.domain.model;

import cc.magicjson.mall.common.domain.AggregateRoot;
import cc.magicjson.mall.common.domain.DomainEvent;
import cc.magicjson.mall.common.domain.ProductId;
import cc.magicjson.mall.common.util.IdGenerator;
import cc.magicjson.mall.order.domain.event.OrderPlacedEvent;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Table(name = "mall_cloud_order")
@Entity
@NoArgsConstructor
@Getter
public class Order implements AggregateRoot<String> {

	@Id
	private String id;

	@Column(name = "customer_id")
	private String customerId;
	@Transient
	private List<OrderLine> orderLines;
	@Enumerated(EnumType.STRING)
	@Column(name = "status")
	private OrderStatus status;
	@Transient
	private List<DomainEvent> domainEvents;

	public Order(String customerId) {
		this.id = IdGenerator.generateId();
		this.customerId = customerId;
		this.orderLines = new ArrayList<>();
		this.status = OrderStatus.CREATED;
		this.domainEvents = new ArrayList<>();
	}


	public void addProduct(ProductId productId, int quantity, Money price) {
		orderLines.add(new OrderLine(productId, quantity, price));
	}

	public void place() {
		if (orderLines.isEmpty()) {
			throw new IllegalStateException("Cannot place an empty order");
		}
		if (this.status != OrderStatus.CREATED) {
			throw new IllegalStateException("Order can only be placed when in CREATED status");
		}
		this.status = OrderStatus.PLACED;
		this.domainEvents.add(new OrderPlacedEvent(this.id, this.customerId));
	}

	public void pay() {
		if (this.status != OrderStatus.PLACED) {
			throw new IllegalStateException("Order can only be paid when in PLACED status");
		}
		this.status = OrderStatus.PAID;
		// You might want to add an OrderPaidEvent here
	}

	public void ship() {
		if (this.status != OrderStatus.PAID) {
			throw new IllegalStateException("Order can only be shipped when in PAID status");
		}
		this.status = OrderStatus.SHIPPED;
		// You might want to add an OrderShippedEvent here
	}

	public void deliver() {
		if (this.status != OrderStatus.SHIPPED) {
			throw new IllegalStateException("Order can only be delivered when in SHIPPED status");
		}
		this.status = OrderStatus.DELIVERED;
		// You might want to add an OrderDeliveredEvent here
	}

	public void cancel() {
		if (this.status == OrderStatus.SHIPPED || this.status == OrderStatus.DELIVERED) {
			throw new IllegalStateException("Cannot cancel an order that has been shipped or delivered");
		}
		this.status = OrderStatus.CANCELLED;
		// You might want to add an OrderCancelledEvent here
	}

	public void refund() {
		if (this.status != OrderStatus.PAID && this.status != OrderStatus.SHIPPED && this.status != OrderStatus.DELIVERED) {
			throw new IllegalStateException("Can only refund orders that have been paid");
		}
		this.status = OrderStatus.REFUNDED;
		// You might want to add an OrderRefundedEvent here
	}


	public List<OrderLine> getOrderLines() {
		return Collections.unmodifiableList(orderLines);
	}

	public OrderStatus getStatus() {
		return status;
	}

	public List<DomainEvent> getDomainEvents() {
		return Collections.unmodifiableList(domainEvents);
	}

	public void clearDomainEvents() {
		this.domainEvents.clear();
	}

	@Override
	public String getId() {
		return id;
	}
}